#include <bits/stdc++.h>

using namespace std;

#include "content.h"
#include "test_runner.h"

const string NAME_SHOW_CONFIG = "show-config:";
const string NAME_SHOW_EXEC_TIME = "show-exec-time:";
const string NAME_FILE_IO = "file-io:";
const string NAME_LOOP = "loop:";
const string NAME_TARGET = "target:";

const string NAME_TEST_MODE = "test-mode:";
const string NAME_USE_TEST_ID = "use-test-id:";
const string NAME_TEST_SAVE_PATH = "test-save-path:";
const string NAME_TEST_POINT_PREFIX = "test-point-prefix:";
const string NAME_TEST_COUNT = "test-count:";

struct Config {
    bool show_config;
    bool show_exec_time;
    bool file_io;
    bool loop;
    string target;

    bool test_mode;
    bool use_test_id;
    string test_point_prefix;
    string test_save_path;
    int test_count;

    Config() :
            show_config(true),
            show_exec_time(true),
            file_io(true),
            loop(false),
            target("slo"),

            test_mode(false),
            use_test_id(true),
            test_point_prefix("test"),
            test_save_path("/test"),
            test_count(-1) {}
};

void load_config(Config& config, const string& config_file_path) {
    ifstream config_file_in(config_file_path);

    string key, val;

    while (config_file_in >> key) {
        config_file_in.get();
        getline(config_file_in, val);
        if (key == NAME_SHOW_CONFIG) {
            config.show_config = val == "true";
        } else if (key == NAME_SHOW_EXEC_TIME) {
            config.show_exec_time = val == "true";
        } else if (key == NAME_FILE_IO) {
            config.file_io = val == "true";
        } else if (key == NAME_LOOP) {
            config.loop = val == "true";
        } else if (key == NAME_TARGET) {
            config.target = val;
        }

        else if (key == NAME_TEST_MODE) {
            config.test_mode = val == "true";
        } else if (key == NAME_USE_TEST_ID) {
            config.use_test_id = val == "true";
        } else if (key == NAME_TEST_POINT_PREFIX) {
            config.test_point_prefix = val;
        } else if (key == NAME_TEST_SAVE_PATH) {
            config.test_save_path = val;
        } else if (key == NAME_TEST_COUNT) {
            stringstream ss(val);
            ss >> config.test_count;
        }
    }

    config_file_in.close();
}

int main() {
    Config config;
    ifstream cpp_in;
    ofstream cpp_out;
    streambuf *cpp_old_in, *cpp_old_out;

    // 加载配置文件
    load_config(config, "config.txt");

    // io重定向
    if (config.file_io) {
        cpp_in.open("in.txt");
        cpp_out.open("out.txt");
        cpp_old_in = cin.rdbuf(cpp_in.rdbuf());
        cpp_old_out = cout.rdbuf(cpp_out.rdbuf());
    }

    // 显示配置
    if (config.show_config) {
        cout << "-----------------Config-----------------" << endl;
        cout << "show-config:\t" << config.show_config << endl;
        cout << "file-io:\t" << config.file_io << endl;
        cout << "loop:\t" << config.loop << endl;
        cout << "target:\t" << config.target << endl << endl;

        cout << "test-mode:\t" << config.test_mode << endl;
        cout << "use-test-id:\t" << config.use_test_id << endl;
        cout << "test-save-path:\t" << config.test_save_path << endl;
        cout << "test-point-prefix:\t" << config.test_point_prefix << endl;
        cout << "test-count:\t" << config.test_count << endl << endl;

        cout << "----------------------------------------" << endl;
    }

    // 测试模式
    if (config.test_mode) {
        Dis::test_runner runner(solve, standard, generator, config.test_save_path);
        runner.set_use_id(config.use_test_id);
        runner.set_test_point_pre(config.test_point_prefix);
        srand(time(nullptr));
        if (runner.run(config.test_count)) {
            cout << "Test Completed." << endl;
        } else {
            cout << "Test Uncompleted." << endl;
        }
    }
    // 编写模式
    else {
        do {
            clock_t start, end;
            start = clock();
            if (config.target == "slo") solve();
            else standard();
            end = clock();
            // 显示运行时间
            if (config.show_exec_time) cout << "Exec Time: " << end - start << "ms." << endl;
        } while (config.loop && !config.file_io);
    }

    // 恢复io重定向
    if (config.file_io) {
        cin.rdbuf(cpp_old_in);
        cout.rdbuf(cpp_old_out);
        cpp_in.close();
        cpp_out.close();
    }

    return 0;
}